package com.hooya.fa.eu.biz.dao.manager.special;

import com.hooya.fa.eu.api.bo.stk.HistoryBelongsBO;
import com.hooya.fa.eu.api.bo.stk.ReturnedRecordBO;
import com.hooya.fa.eu.api.bo.stk.SellRecordBO;
import com.hooya.fa.eu.api.enums.CkEnum;
import com.hooya.fa.eu.biz.dao.entity.*;
import com.hooya.fa.eu.biz.dao.manager.GeneratorEntityManager;
import com.hooya.integrated.common.core.util.BeanCopyUtils;
import com.hooya.integrated.common.core.util.RedisUtils;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.hooya.fa.eu.api.constant.DictConstant.DICT_PREFIX;
import static com.hooya.fa.eu.api.constant.DictConstant.companyMap;
import static com.hooya.fa.eu.api.util.MapUtil.reverseValue;

/**
 * @Description 销售Manager
 * @Author : Zongz
 * @Copyright Copyright (c) 豪雅集团
 * @Create 2024/3/7
 * @Version 1.0.0
 */
@Slf4j
@Component
@AllArgsConstructor
public class XsDataManager {

    private final GeneratorEntityManager entityManager;

    public void deductSellData(List<SellRecordBO> curSellData,
                               List<HistoryBelongsBO> hisBelongList,
                               List<HistoryBelongsBO> fbaHisBelongList,
                               List<TempKcjlDaily> inventoryList,
                               List<TempXsjl> tempXsjlList,
                               List<TradeRecord> tradeRecordList,
                               List<TempXsjlAbnormal> tempXsjlAbnormalList,
                               Map<String, String> metaWarehouseMap, AtomicInteger deleteFdsXsjl) {
        curSellData = curSellData.stream().sorted(Comparator.comparing(SellRecordBO::getSheetNumber))
                .collect(Collectors.toList());
        Map<String, List<String>> fbaCkFdsMap =
                new TreeMap<>(RedisUtils.hmget(DICT_PREFIX + CkEnum.FBA_CK_REVERSAL_MAP.getName()));
        Set<String> xsOtherCkList = RedisUtils.sGet(DICT_PREFIX + CkEnum.XS_OTHER_LIST.getName());
        //记录销售记录中toCountry为--的数据
        List<String> unknownToCountries = new ArrayList<>();
        for (SellRecordBO xs : curSellData) {
            //去除货权优先级
//            List<String> hqList;
//            if (xs.getCompany().equals("costway")) {
//                hqList = CompanyEnum.getCompanyList();
//            } else {
//                hqList = CompanyEnum.getCompanyListBySort();
//            }
            if ("--".equals(xs.getToCountry())) {
                unknownToCountries.add(xs.getSheetNumber());
            }
            //正常减扣，扣到0为止
            int sl = deductRelationHqSellData(xs, xs.getSl(), inventoryList, tempXsjlList,
                    tradeRecordList, false);
            //正常减扣，减扣至负数【(sl != slMemo)优化用】
            if (sl > 0) {
                sl = deductRelationHqSellData(xs, sl, inventoryList, tempXsjlList, tradeRecordList,
                        true);
            }
            //当前库存记录没有对应产品编号的，根据restock进行处理
            if (sl > 0) {
                if (Arrays.asList("FBA", "FBC", "FBM", "FBK").contains(xs.getRestockMark())) {
                    //去除货权优先级
                    List<HistoryBelongsBO> list = fbaHisBelongList.stream().filter(l ->
                            l.getCpbh().equals(xs.getCpbh())).collect(Collectors.toList());

                    //1.匹配销售记录仓库
                    List<HistoryBelongsBO> matchingList = list.stream()
                            .filter(l -> l.getPlace().equals(xs.getChck()))
                            .collect(Collectors.toList());
                    //匹配chck对应国家历史货权，匹配不到加入到异常销售记录
                    if (getRankedBelongsAndProcess(matchingList, xs, sl, tempXsjlList, tradeRecordList, inventoryList, metaWarehouseMap)) {
                        continue;
                    }
                    //2.匹配FBA仓库
                    List<String> ckList = fbaCkFdsMap.get(xs.getRestockMark());
                    List<HistoryBelongsBO> matchingFbaCkList = list.stream()
                            .filter(e -> ckList.contains(e.getPlace()))
                            .collect(Collectors.toList());
                    //匹配chck对应国家历史货权，匹配不到加入到异常销售记录
                    if (getRankedBelongsAndProcess(matchingFbaCkList, xs, sl, tempXsjlList, tradeRecordList, inventoryList, metaWarehouseMap)) {
                        continue;
                    }
                    dealWithAbnormalSellRecord(xs, sl, deleteFdsXsjl, tempXsjlAbnormalList);
                } else if ("SFA".equals(xs.getRestockMark())) {
                    List<HistoryBelongsBO> list = hisBelongList.stream().filter(l ->
                                    l.getCpbh().equals(xs.getCpbh()) && l.getPlace().equals(xs.getChck()))
                            .collect(Collectors.toList());
                    //匹配chck对应国家历史货权，匹配不到加入到异常销售记录
                    if (getRankedBelongsAndProcess(list, xs, sl, tempXsjlList, tradeRecordList, inventoryList, metaWarehouseMap)) {
                        continue;
                    }
                    dealWithAbnormalSellRecord(xs, sl, deleteFdsXsjl, tempXsjlAbnormalList);
                } else {
                    if (!Arrays.asList("fds", "costway").contains(xs.getCompany()) ||
                            ("fds".equals(xs.getCompany()) && deleteFdsXsjl.get() + sl <= 800)) {
                        dealWithAbnormalSellRecord(xs, sl, deleteFdsXsjl, tempXsjlAbnormalList);
                    } else {
                        List<HistoryBelongsBO> list = hisBelongList.stream().filter(l ->
                                        l.getCpbh().equals(xs.getCpbh()) && l.getPlace().equals(xs.getChck()))
                                .collect(Collectors.toList());
                        //匹配chck对应国家历史货权，匹配不到加入到异常销售记录
                        if (getRankedBelongsAndProcess(list, xs, sl, tempXsjlList, tradeRecordList, inventoryList, metaWarehouseMap)) {
                            continue;
                        }
                        List<TempKcjlDaily> otherCkList = inventoryList.stream().filter(
                                        l -> l.getCpbh().equals(xs.getCpbh()) && xsOtherCkList.contains(l.getPlace()))
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(otherCkList)) {
                            log.info(xs + "\n 该销售单会放置到其他仓");
                            dealWithAbnormalSellRecord(xs, sl, deleteFdsXsjl, tempXsjlAbnormalList);
                            //注释解释：转运单完成之前，所在货权仓库的sku不存在，杜绝最终到其他仓库找到的情况，直接扔掉，放到以后去补
                            /*String hq;
                            String place;
                            //优化
                            if (otherCkList.size() == 1) {
                                hq = otherCkList.get(0).getBelongs();
                                place = otherCkList.get(0).getPlace();
                            } else {
                                TempKcjlDaily rankHisBelongs = otherCkList.stream()
                                        .min((e1, e2) -> {
                                            int rank1 = hqList.indexOf(e1.getBelongs());
                                            int rank2 = hqList.indexOf(e2.getBelongs());
                                            return Integer.compare(rank1, rank2);
                                        }).get();
                                hq = rankHisBelongs.getBelongs();
                                place = rankHisBelongs.getPlace();
                            }
                            dealWithOtherKcXs(hq, place, sl, inventoryList, xs, tempXsjlList, tradeRecordList);*/
                            continue;
                        }
                        dealWithAbnormalSellRecord(xs, sl, deleteFdsXsjl, tempXsjlAbnormalList);
                    }
                }
            }
        }
        XxlJobHelper.log("销售记录中tocountry为--的数据:{}", unknownToCountries.toString());
    }

    /**
     * 处理从历史货权中得到的集合数据，判断货权，扣减与restockMark相关的的销售数据
     *
     * @param list            匹配到的历史货权集合(cpbh、仓库)
     * @param xs              当前销售记录
     * @param sl              销售数量
     * @param tempXsjlList    销售记录集合
     * @param tradeRecordList 买卖记录集合
     * @param inventoryList   库存记录集合
     * @return 返回布尔值, false说明当前销售记录不符合规则，为异常销售记录 进入dealWithAbnormalSellRecord
     */
    public boolean getRankedBelongsAndProcess(List<HistoryBelongsBO> list,
                                              SellRecordBO xs,
                                              int sl,
                                              List<TempXsjl> tempXsjlList,
                                              List<TradeRecord> tradeRecordList,
                                              List<TempKcjlDaily> inventoryList, Map<String, String> metaWarehouseMap) {
        if (!CollectionUtils.isEmpty(list)) {
            // 优先查找符合“belongs结尾为fromcountry”的历史货权
            String originCountry = metaWarehouseMap.get(xs.getChck());
            String realHqBelongs = list.stream()
                    .map(HistoryBelongsBO::getBelongs)
                    .filter(belongs -> belongs.endsWith(originCountry))
                    .findFirst()
                    .orElse("");
            if (StringUtils.isNotBlank(realHqBelongs)) {
                deductRelationRestockMarkSellData(xs, sl, realHqBelongs, tempXsjlList, inventoryList, tradeRecordList);
                return true;
            }
        }
        //找不到符合chck对应国家要求的历史货权，进入后续异常销售记录
        return false;
    }

    /**
     * 处理其他仓库的销售数据
     *
     * @param hq              货权
     * @param place           出库地
     * @param sl              数量
     * @param inventoryList   仓库
     * @param xs              销售数据
     * @param tempXsjlList    销售记录集合
     * @param tradeRecordList 交易记录集合
     */
    void dealWithOtherKcXs(String hq, String place, int sl, List<TempKcjlDaily> inventoryList,
                           SellRecordBO xs, List<TempXsjl> tempXsjlList, List<TradeRecord> tradeRecordList) {
        inventoryList.stream().filter(l -> l.getCpbh().equals(xs.getCpbh()) &&
                        l.getBelongs().equals(hq) && l.getPlace().equals(place))
                .forEach(l -> l.setSl(l.getSl() - sl));
        TempXsjl tempXsjl = BeanCopyUtils.copyPropertiesNew(
                xs, TempXsjl::new, (s, t) -> {
                    t.setBelongs(hq);
                    t.setChck(place);
                    t.setSl(sl);
                });
        tempXsjlList.add(tempXsjl);
        if (!xs.getCompany().equals(hq.split("-")[0].toLowerCase())) {
            xs.setPlace(place);
            tradeRecordList.add(entityManager.genTradeRecord(xs, sl,
                    hq.toLowerCase(), xs.getCompany(), xs.getFromCountry(),
                    xs.getToCountry(), ""));
        }
    }

    void dealWithAbnormalSellRecord(SellRecordBO xs, int sl, AtomicInteger deleteFdsXsjl,
                                    List<TempXsjlAbnormal> tempXsjlAbnormalList) {
        TempXsjlAbnormal abnormal = BeanCopyUtils.copyPropertiesNew(xs,
                TempXsjlAbnormal::new, (s, t) -> {
                    t.setSl(sl);
                    t.setCreateTime(new Date());
                });
        tempXsjlAbnormalList.add(abnormal);
        if (xs.getCompany().equals("fds")) {
            deleteFdsXsjl.addAndGet(sl);
        }
    }

    /**
     * 扣减与restockMark相关的的销售数据
     *
     * @param xs              销售数据
     * @param sl              数量
     * @param hq              货权
     * @param tempXsjlList    销售记录集合
     * @param inventoryList   库存数量
     * @param tradeRecordList 交易记录
     * @return
     */
    int deductRelationRestockMarkSellData(SellRecordBO xs, int sl, String hq, List<TempXsjl> tempXsjlList,
                                          List<TempKcjlDaily> inventoryList, List<TradeRecord> tradeRecordList) {
        TempXsjl tempXsjl = BeanCopyUtils.copyPropertiesNew(xs, TempXsjl::new, (s, t) -> {
            t.setSl(sl);
            t.setBelongs(hq);
            t.setCpbh(s.getCpbh());
            t.setCreateTime(new Date());
        });
        tempXsjlList.add(tempXsjl);
        inventoryList.add(entityManager.genTempKcjlDaily(xs.getCpbh(), hq, xs.getChck(), -sl, xs.getOrderDate()));
        if (!xs.getCompany().equals(hq.split("-")[0].toLowerCase())) {
            xs.setPlace(xs.getChck());
            tradeRecordList.add(entityManager.genTradeRecord(xs, sl, hq.toLowerCase(), xs.getCompany(),
                    xs.getFromCountry(), xs.getToCountry(), ""));
        }
        return 0;
    }

    /**
     * 减扣货权相关销售数据 todo：(for循环可优化)
     *
     * @param xs              销售数据
     * @param sl              减扣的数量
     * @param hqList          货权列表
     * @param inventoryList   库存数据
     * @param tempXsjlList    销售记录集合
     * @param tradeRecordList 买卖记录集合
     * @param second          是否第二次不根据库存数量进行减扣（第一次扣减知道0为止）
     * @return
     */
    private int deductRelationHqSellData(SellRecordBO xs, int sl,
                                         List<TempKcjlDaily> inventoryList, List<TempXsjl> tempXsjlList,
                                         List<TradeRecord> tradeRecordList, boolean second) {
        //获取对应库存记录集合
        List<TempKcjlDaily> kcList = inventoryList.stream().filter(l -> l.getPlace().equals(xs.getChck()) &&
                l.getCpbh().equals(xs.getCpbh())).collect(Collectors.toList());
        for (TempKcjlDaily tempKcjlDaily : kcList) {
            String hq = tempKcjlDaily.getBelongs();
            int kcsl;
            int num;
            //直接从筛选后数据中获取
            kcsl = kcList.stream().filter(l -> l.getPlace().equals(xs.getChck()) &&
                            l.getCpbh().equals(xs.getCpbh()) && l.getBelongs().equals(hq))
                    .mapToInt(TempKcjlDaily::getSl).sum();
            if (second) {
                //直接减扣，使库存为负
                if (kcsl > 0) {
                    System.out.println("校验用，第二次数量：" + kcsl);
                }
                num = sl;
                sl = kcsl - sl;
            } else {
                //防止不同包裹，相同产品，在kc已经为负的时候，进行正常扣减
                if (kcsl <= 0) {
                    continue;
                }
                sl = sl - kcsl;
                num = sl < 0 ? xs.getSl() : kcsl;
            }
            TempXsjl tempXsjl = BeanCopyUtils.copyPropertiesNew(xs, TempXsjl::new, (s, t) -> {
                t.setSl(num);
                t.setBelongs(hq);
                t.setCreateTime(new Date());
            });
            tempXsjlList.add(tempXsjl);
            inventoryList.stream().filter(l -> l.getPlace().equals(xs.getChck()) &&
                            l.getCpbh().equals(xs.getCpbh()) && l.getBelongs().equals(hq))
                    .forEach(l -> l.setSl(l.getSl() - num));
            if (!xs.getCompany().equals(hq.split("-")[0].toLowerCase())) {
                xs.setPlace(xs.getChck());
                tradeRecordList.add(entityManager.genTradeRecord(xs, num, hq.toLowerCase(),
                        xs.getCompany(), xs.getFromCountry(), xs.getToCountry(), ""));
            }
            xs.setSl(Math.max(sl, 0));
            //在第一次扣减时，只有sl扣减完才能跳出循环，
            //做第二次扣减时，就是要将数量扣减完，做后续的pkpy
            if (sl <= 0) {
                return 0;
            }
        }
        return sl;
    }

    /**
     * @param curDate         当天日期
     * @param hisBelongList   历史非fba货权数据
     * @param inventoryList   仓库数据
     * @param resReturnedList 所有退货数据
     * @param curSellData     当日销售数据
     * @param tempThjlList    退货记录集合
     * @param tempXsjlList    销售记录集合
     */
    public void dealWithSellData(String curDate, List<SellRecordBO> curSellData,
                                 List<HistoryBelongsBO> hisBelongList, List<TempKcjlDaily> inventoryList,
                                 List<ReturnedRecordBO> resReturnedList, Map<String, String> metaWarehouseMap,
                                 List<TempThjl> tempThjlList, List<TempXsjl> tempXsjlList) {

        //当日退货数据
        List<ReturnedRecordBO> curThData = resReturnedList.stream()
                .filter(l -> l.getOrderDate().equals(curDate))
                .sorted(Comparator.comparing(ReturnedRecordBO::getSku)).collect(Collectors.toList());
        //退货与销售的匹配
        for (ReturnedRecordBO th : curThData) {
            //当日是否有退货的
            List<SellRecordBO> thXsjl = curSellData.stream().filter(l -> l.getCpbh().equals(th.getSku()) &&
                            l.getChck().equals(th.getPlace()) && l.getCompany().equals(th.getCompany()))
                    .sorted(Comparator.comparing(SellRecordBO::getSl))
                    .collect(Collectors.toList());
            String toCkOrigin = metaWarehouseMap.get(th.getPlace());
            Map<String, Integer> sortedMap;
            if (th.getCompany().equalsIgnoreCase("costway")) {
                sortedMap = reverseValue(companyMap, true);
            } else {
                sortedMap = reverseValue(companyMap, false);
            }
            if (CollectionUtils.isEmpty(thXsjl)) {
                restockMatchSellData(sortedMap, hisBelongList, th, inventoryList, tempThjlList,
                        toCkOrigin);
            } else {
                int thNum = dealWithCurThData(th, curSellData, thXsjl, tempXsjlList, tempThjlList);
                if (thNum > 0) {
                    restockMatchSellData(sortedMap, hisBelongList, th, inventoryList, tempThjlList,
                            toCkOrigin);
                }
            }
        }
        //销售订单扣除
    }

    private void restockMatchSellData(Map<String, Integer> companyMap, List<HistoryBelongsBO> hisBelongList,
                                      ReturnedRecordBO th, List<TempKcjlDaily> inventoryList,
                                      List<TempThjl> tempThjlList, String toCkOrigin) {
        try {
            companyMap.forEach((k, v) -> {
                if (hisBelongList.stream().anyMatch(l -> l.getCpbh().equals(th.getSku()) &&
                        l.getBelongs().contains(k))) {
                    dealWithXsData(1 == v, th, inventoryList, tempThjlList, toCkOrigin);
                    throw new RuntimeException("over");
                }
            });
        } catch (RuntimeException e) {
            if (!"over".equals(e.getMessage())) {
                log.error(e.getMessage());
                throw e; // 如果不是我们抛出的异常，则重新抛出
            }
        }
    }

    private void dealWithXsData(boolean fdsData, ReturnedRecordBO th, List<TempKcjlDaily> inventoryList,
                                List<TempThjl> tempThjlList, String toCkOrigin) {
        String newBelongs;
        if (!fdsData) {
            newBelongs = "COSTWAY-" + toCkOrigin;
        } else {
            newBelongs = "FDS-" + toCkOrigin;
        }
        String finalNewBelongs = newBelongs;
        if (inventoryList.stream().anyMatch(l -> l.getCpbh().equals(th.getSku()) &&
                l.getPlace().equals(th.getPlace()) && l.getBelongs().equals(finalNewBelongs))) {
            inventoryList.stream().filter(l -> l.getCpbh().equals(th.getSku()) &&
                            l.getPlace().equals(th.getPlace()) && l.getBelongs().equals(finalNewBelongs))
                    .forEach(l -> l.setSl(l.getSl() + th.getSl()));
        } else {
            inventoryList.add(
                    entityManager.genTempKcjlDaily(th.getSku(), newBelongs, th.getPlace(),
                            th.getSl(), th.getOrderDate()));
        }
        tempThjlList.add(entityManager.gentempThjl(th, newBelongs, "addkc", th.getSl()));
    }


    /**
     * @param th              退货数据
     * @param curSellData     当天销售
     * @param restockSellData 退货销售
     * @param tempXsjlList    销售记录集合
     * @param tempThjlList    退货记录集合
     * @return 退货数量
     */
    private int dealWithCurThData(ReturnedRecordBO th, List<SellRecordBO> curSellData,
                                  List<SellRecordBO> restockSellData, List<TempXsjl> tempXsjlList,
                                  List<TempThjl> tempThjlList) {
        int num = 0;
        int sl = th.getSl();
        for (SellRecordBO sell : restockSellData) {
            int xsNum = sell.getSl();
            num = sl - xsNum;
            int finalNum = num < 0 ? th.getSl() : xsNum;
            TempXsjl tempXsjl = BeanCopyUtils.copyPropertiesNew(sell, TempXsjl::new, (s, t) -> {
                t.setCpbh(s.getCpbh());
                t.setBelongs(th.getCompany().toUpperCase());
                t.setSl(finalNum);
            });
            tempXsjlList.add(tempXsjl);
            if (num < 0) {
                curSellData.stream().filter(l -> l.getSheetNumber().equals(sell.getSheetNumber()))
                        .forEach(l -> l.setSl(l.getSl() - th.getSl()));
            } else {
                curSellData.remove(sell);
            }
            tempThjlList.add(entityManager.gentempThjl(th, tempXsjl.getCompany().toUpperCase(), "addxs", finalNum));
            //临界值0
            if (num <= 0) {
                break;
            }
            sl = num;
        }
        return Math.max(num, 0);
    }

}
